module run_module(
    input clk,                  //100MHZ
    input [1:0] dir,           //按下的运动方向
    input [1:0] dir1,           //按下的运动方向
    input [1:0] game_state,    //游戏状态：0 开始界面， 1 游戏中， 2 结束界面
    input [9:0] cur_x,         // VGA当前X坐标
    input [8:0] cur_y,         // VGA当前Y坐标
    output [2:0] one_state,    //(X,Y)坐标对应
    output reg gameover,       //传出游戏结束的信息
    output reg [15:0] score,    //得分
    output [2:0] fruit_state    //食物类型
);

// 参数定义
parameter MAX_LENGTH = 100;
parameter MAX_CNT = 23;

// 寄存器定义
reg [5:0] head_x;
reg [4:0] head_y;              //蛇头的坐标
reg [5:0] next_head_x;
reg [4:0] next_head_y;         //下一刻蛇头的坐标
reg [5:0] head_x1;
reg [4:0] head_y1;              //蛇头的坐标
reg [5:0] next_head_x1;
reg [4:0] next_head_y1;         //下一刻蛇头的坐标
reg [5:0] fruit_x;
reg [4:0] fruit_y;             //食物坐标
reg [5:0] body_x [MAX_LENGTH:0];
reg [4:0] body_y [MAX_LENGTH:0]; //存储蛇身坐标的数组
reg [5:0] body_x1 [MAX_LENGTH:0];
reg [4:0] body_y1 [MAX_LENGTH:0]; //存储蛇身坐标的数组
reg [1:0] current_dir;         //当前蛇运动的方向
reg [1:0] current_dir1;         //当前蛇运动的方向
reg [2:0] state [0:39][0:29];  //所有单元的状态信息
reg [23:0] cnt;                //计数以分频
reg [1:0] state_pos;           //存储上一刻和当前的游戏状态
reg [2:0] fruit_type;          //当前食物类型 (00:小, 01:中, 10:大)

// 线网定义
wire game_clk;                 //游戏频率（速度）

// 整数变量
integer length;
integer length1;
integer i, j, k;

// 时钟分频和输出赋值
assign game_clk = cnt[MAX_CNT];
assign one_state = state[state_x_addr(cur_x)][state_y_addr(cur_y)];
assign fruit_state = fruit_type; 

// 时钟计数器
always @(posedge clk) begin
    cnt <= cnt + 24'b1;
end

// 计算转换后的对应单元格坐标
function [5:0] state_x_addr;
    input [9:0] pix_x;
    begin
        state_x_addr = pix_x >> 4; // x坐标右移4位，相当于除以16
    end
endfunction

function [5:0] state_y_addr;
    input [8:0] pix_y;
    begin
        state_y_addr = pix_y >> 4; // y坐标右移4位，相当于除以16
    end
endfunction

// 初始化
initial begin
    cnt = 24'b0;
    state_pos = 2'b00;
    head_x = 6'd20;
    head_y = 5'd6;
    next_head_x = 6'd21;
    next_head_y = 5'd6;
    head_x1 = 6'd20;
    head_y1 = 5'd23;
    next_head_x1 = 6'd21;
    next_head_y1 = 5'd23;
    length = 1'd1;
    length1 = 1'd1;
    fruit_x = 6'd22;
    fruit_y = 5'd6;
    body_x[0] = 6'd19;
    body_y[0] = 6'd6;
    body_x[1] = 6'd18;
    body_y[1] = 6'd6;
    body_x1[0] = 6'd19;
    body_y1[0] = 6'd23;
    body_x1[1] = 6'd18;
    body_y1[1] = 6'd23;
    current_dir = 2'd3;
    current_dir1 = 2'd3;
    score = 16'd0;
    gameover = 1'b0;
    fruit_type = 3'b001;

    // 初始化所有单元格为空白
    for (i=0; i<40; i=i+1) begin
        for (j=0; j<30; j=j+1) begin
            state[i][j] = 3'b000;
        end
    end
    
    // 设置边界墙壁
    i = 0;
    for (j=0; j<30; j=j+1) begin
        state[i][j] = 3'b110; //state = 6为死亡格
    end
    i = 39;
    for (j=0; j<30; j=j+1) begin
        state[i][j] = 3'b110; //state = 6为死亡格
    end
    j = 0;
    for (i=0; i<40; i=i+1) begin
        state[i][j] = 3'b110; //state = 6为死亡格
    end
    j = 29;
    for (i=0; i<40; i=i+1) begin
        state[i][j] = 3'b110; //state = 6为死亡格
    end

    // 初始化身体数组其余部分
    for (i=2; i<100; i=i+1) begin
        body_x[i] = 6'd0;
        body_y[i] = 5'd0;
        body_x1[i] = 6'd0;
        body_y1[i] = 5'd0;
    end
    
    // 增加场内障碍物
    // 中心十字障碍
    for (i=18; i<=22; i=i+1) state[i][15] = 3'b110; // 水平条
    for (j=13; j<=17; j=j+1) state[20][j] = 3'b110; // 垂直条

    // 四个对称的矩形障碍
    // 左上矩形
    for (i=5; i<=7; i=i+1) begin
        for (j=5; j<=7; j=j+1) begin
            state[i][j] = 3'b110;
        end
    end

    // 右上矩形
    for (i=32; i<=34; i=i+1) begin
        for (j=5; j<=7; j=j+1) begin
            state[i][j] = 3'b110;
        end
    end

    // 左下矩形
    for (i=5; i<=7; i=i+1) begin
        for (j=22; j<=24; j=j+1) begin
            state[i][j] = 3'b110;
        end
    end

    // 右下矩形
    for (i=32; i<=34; i=i+1) begin
        for (j=22; j<=24; j=j+1) begin
            state[i][j] = 3'b110;
        end
    end

    
    // 设置蛇的初始位置
    state[20][6] = 3'b001;  // 蛇头
    state[19][6] = 3'b010;  // 蛇身
    state[18][6] = 3'b010;  // 蛇身
    state[20][23] = 3'b001;  // 蛇头
    state[19][23] = 3'b010;  // 蛇身
    state[18][23] = 3'b010;  // 蛇身
    state[29][6] = 3'b011;  // 食物
end

// 主要游戏逻辑
always @(posedge game_clk) begin
    if (game_state[0] == 1'b1 || game_clk == 1'b1) begin
        state_pos <= {state_pos[0], game_state[0]};
        
        // 游戏重置逻辑
        if(state_pos == 2'b01) begin
            head_x <= 6'd20;
            head_y <= 5'd6;
            length <= 1'd1;
            fruit_x <= 6'd29;
            fruit_y <= 5'd6;
            body_x[0] <= 6'd19;
            body_y[0] <= 6'd6;
            body_x[1] <= 6'd18;
            body_y[1] <= 6'd6;
            current_dir <= 2'd3;

            head_x1 <= 6'd20;
            head_y1 <= 5'd23;
            length1 <= 1'd1;
            body_x1[0] <= 6'd19;
            body_y1[0] <= 6'd23;
            body_x1[1] <= 6'd18;
            body_y1[1] <= 6'd23;
            current_dir1 <= 2'd3;
            score <= 16'd0;
            gameover <= 1'b0;
            fruit_type <= 3'b001;

            // 重置所有单元格
            for (i = 0; i < 40; i = i + 1) begin
                for (j = 0; j < 30; j = j + 1) begin
                    state[i][j] <= 3'b000;
                end
            end
            
            // 重新设置边界墙壁
            i = 0;
            for (j = 0; j < 30; j = j + 1) begin
                state[i][j] <= 3'b110;
            end
            i = 39;
            for (j = 0; j < 30; j = j + 1) begin
                state[i][j] <= 3'b110;
            end
            j = 0;
            for (i = 0; i < 40; i = i + 1) begin
                state[i][j] <= 3'b110;
            end
            j = 29;
            for (i = 0; i < 40; i = i + 1) begin
                state[i][j] <= 3'b110;
            end

            // 重置身体数组
            for (i = 2; i < 100; i = i + 1) begin
                body_x[i] <= 6'd0;
                body_y[i] <= 5'd0;
            end

            for (i = 2; i < 100; i = i + 1) begin
                body_x1[i] <= 6'd0;
                body_y1[i] <= 5'd0;
            end


            // 重新设置障碍物（与初始化部分相同）
            // 中心十字障碍
            for (i=18; i<=22; i=i+1) state[i][15] <= 3'b110; // 水平条
            for (j=13; j<=17; j=j+1) state[20][j] <= 3'b110; // 垂直条

            // 四个对称的矩形障碍
            // 左上矩形
            for (i=5; i<=7; i=i+1) begin
                for (j=5; j<=7; j=j+1) begin
                    state[i][j] <= 3'b110;
                end
            end

            // 右上矩形
            for (i=32; i<=34; i=i+1) begin
                for (j=5; j<=7; j=j+1) begin
                    state[i][j] <= 3'b110;
                end
            end

            // 左下矩形
            for (i=5; i<=7; i=i+1) begin
                for (j=22; j<=24; j=j+1) begin
                    state[i][j] <= 3'b110;
                end
            end

            // 右下矩形
            for (i=32; i<=34; i=i+1) begin
                for (j=22; j<=24; j=j+1) begin
                    state[i][j] <= 3'b110;
                end
            end
                        
            // 设置蛇的位置
            state[20][6] <= 3'b001;
            state[19][6] <= 3'b010;
            state[18][6] <= 3'b010;
            state[29][6] <= 3'b011;
            // 设置蛇的位置
            state[20][23] <= 3'b001;
            state[19][23] <= 3'b010;
            state[18][23] <= 3'b010;
            
        end else if (game_clk) begin
            if (game_state[0]) begin
                // 方向控制 - 计算下一个蛇头位置
                case(current_dir)
                    2'd0: begin
                        next_head_x = head_x;
                        next_head_y = head_y - 1; //0 向上移动
                    end
                    2'd1: begin
                        next_head_x = head_x;
                        next_head_y = head_y + 1; //1 向下移动
                    end
                    2'd2: begin
                        next_head_x = head_x - 1;
                        next_head_y = head_y;     //2 向左移动
                    end
                    2'd3: begin
                        next_head_x = head_x + 1;
                        next_head_y = head_y;     //3 向右移动
                    end
                endcase

                // 处理输入方向，防止反向移动
                case(dir)
                    2'd0: if (current_dir != 2'd1) current_dir <= 2'd0;
                    2'd1: if (current_dir != 2'd0) current_dir <= 2'd1;
                    2'd2: if (current_dir != 2'd3) current_dir <= 2'd2;
                    2'd3: if (current_dir != 2'd2) current_dir <= 2'd3;
                endcase

                case(current_dir1)
                    2'd0: begin
                        next_head_x1 = head_x1;
                        next_head_y1 = head_y1 - 1; //0 向上移动
                    end
                    2'd1: begin
                        next_head_x1 = head_x1;
                        next_head_y1 = head_y1 + 1; //1 向下移动
                    end
                    2'd2: begin
                        next_head_x1 = head_x1 - 1;
                        next_head_y1 = head_y1;     //2 向左移动
                    end
                    2'd3: begin
                        next_head_x1 = head_x1 + 1;
                        next_head_y1 = head_y1;     //3 向右移动
                    end
                endcase

                // 处理输入方向，防止反向移动
                case(dir1)
                    2'd0: if (current_dir1 != 2'd1) current_dir1 <= 2'd0;
                    2'd1: if (current_dir1 != 2'd0) current_dir1 <= 2'd1;
                    2'd2: if (current_dir1 != 2'd3) current_dir1 <= 2'd2;
                    2'd3: if (current_dir1 != 2'd2) current_dir1 <= 2'd3;
                endcase


                // 检查碰撞 - 障碍物或蛇身
                if (state[next_head_x][next_head_y] == 3'b110 || state[next_head_x][next_head_y] == 3'b010) begin
                    gameover <= 1'b1;
                end 
                // 移动到空白格
                else if (state[next_head_x][next_head_y] == 3'b000) begin
                    state[next_head_x][next_head_y] <= 3'b001; //下一格变为蛇头
                    state[head_x][head_y] <= 3'b010;           //原蛇头处变为蛇身
                    state[body_x[length]][body_y[length]] <= 3'b000; //蛇尾变为空白
                    
                    // 挪动身体数组
                    for (i = MAX_LENGTH; i > 0; i = i - 1) begin
                        body_x[i] <= body_x[i - 1];
                        body_y[i] <= body_y[i - 1];
                    end
                    body_x[0] <= head_x;
                    body_y[0] <= head_y;
                    head_x <= next_head_x;
                    head_y <= next_head_y;
                end 
                // 吃到食物
                else begin
                    // 根据食物类型加分
                    case (state[next_head_x][next_head_y])
                        3'b011: score <= score + 16'd1;  // 小食物 +1分
                        3'b100: score <= score + 16'd2;  // 中食物 +2分
                        3'b101: score <= score + 16'd3;  // 大食物 +3分
                    endcase
                    
                    length <= length + 1'd1;  // 增加长度
                    state[next_head_x][next_head_y] <= 3'b001; // 新蛇头
                    state[head_x][head_y] <= 3'b010;           // 原蛇头变蛇身
                    
                    // 挪动身体数组（吃食物时不删除蛇尾）
                    for(i = MAX_LENGTH; i > 0; i = i - 1) begin
                        body_x[i] <= body_x[i - 1];
                        body_y[i] <= body_y[i - 1];
                    end
                    body_x[0] <= head_x;
                    body_y[0] <= head_y;
                    head_x <= next_head_x;
                    head_y <= next_head_y;

                    // 生成新食物
                    j = 0;
                    for (i = 1; i <= 40 && state[fruit_x][fruit_y] != 3'b000; i = i + 1) begin
                        fruit_x = (fruit_x + 7 + i) % 38 + 1;  // 避开边界
                        fruit_y = (fruit_y + 11 + j) % 28 + 1; // 避开边界
                        if (j <= 30) begin
                            j = j + 1;
                        end else begin
                            j = 0;
                        end
                    end
                    
                    // 随机确定食物类型
                   case ((i + j) % 6)
                        3'd0, 3'd1, 3'd2: begin
                            state[fruit_x][fruit_y] = 3'b011; // 小食物
                            fruit_type = 3'b001; // 小食物
                        end
                        3'd3, 3'd4: begin
                            state[fruit_x][fruit_y] = 3'b100; // 中食物
                            fruit_type = 3'b010; // 中食物
                        end
                        3'd5: begin
                            state[fruit_x][fruit_y] = 3'b101; // 大食物
                            fruit_type = 3'b100; // 大食物
                        end
                    endcase
                end

                if (state[next_head_x1][next_head_y1] == 3'b110 || state[next_head_x1][next_head_y1] == 3'b010) begin
                    gameover <= 1'b1;
                end 
                // 移动到空白格
                else if (state[next_head_x1][next_head_y1] == 3'b000) begin
                    state[next_head_x1][next_head_y1] <= 3'b001; //下一格变为蛇头
                    state[head_x1][head_y1] <= 3'b010;           //原蛇头处变为蛇身
                    state[body_x1[length1]][body_y1[length1]] <= 3'b000; //蛇尾变为空白
                    
                    // 挪动身体数组
                    for (i = MAX_LENGTH; i > 0; i = i - 1) begin
                        body_x1[i] <= body_x1[i - 1];
                        body_y1[i] <= body_y1[i - 1];
                    end
                    body_x1[0] <= head_x1;
                    body_y1[0] <= head_y1;
                    head_x1 <= next_head_x1;
                    head_y1 <= next_head_y1;
                end 
                // 吃到食物
                else begin
                    // 根据食物类型加
                    
                    length1 <= length1 + 1'd1;  // 增加长度
                    state[next_head_x1][next_head_y1] <= 3'b001; // 新蛇头
                    state[head_x1][head_y1] <= 3'b010;           // 原蛇头变蛇身
                    
                    // 挪动身体数组（吃食物时不删除蛇尾）
                    for(i = MAX_LENGTH; i > 0; i = i - 1) begin
                        body_x1[i] <= body_x1[i - 1];
                        body_y1[i] <= body_y1[i - 1];
                    end
                    body_x1[0] <= head_x1;
                    body_y1[0] <= head_y1;
                    head_x1 <= next_head_x1;
                    head_y1 <= next_head_y1;

                    // 生成新食物
                    j = 0;
                    for (i = 1; i <= 40 && state[fruit_x][fruit_y] != 3'b000; i = i + 1) begin
                        fruit_x = (fruit_x + 7 + i) % 38 + 1;  // 避开边界
                        fruit_y = (fruit_y + 11 + j) % 28 + 1; // 避开边界
                        if (j <= 30) begin
                            j = j + 1;
                        end else begin
                            j = 0;
                        end
                    end
                    
                    // 随机确定食物类型
                   case ((i + j) % 6)
                        3'd0, 3'd1, 3'd2: begin
                            state[fruit_x][fruit_y] = 3'b011; // 小食物
                            fruit_type = 3'b001; // 小食物
                        end
                        3'd3, 3'd4: begin
                            state[fruit_x][fruit_y] = 3'b100; // 中食物
                            fruit_type = 3'b010; // 中食物
                        end
                        3'd5: begin
                            state[fruit_x][fruit_y] = 3'b101; // 大食物
                            fruit_type = 3'b100; // 大食物
                        end
                    endcase
                end

            end
        end
    end
end


endmodule